home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / vidhrdw / tms34061.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  7KB  |  300 lines

  1. /****************************************************************************
  2.  *                                                                            *
  3.  *    Functions to emulate the TMS34061 video controller                        *
  4.  *                                                                            *
  5.  *  Created by Zsolt Vasvari on 5/26/1998.                                    *
  6.  *                                                                            *
  7.  *  This is far from complete. See the TMS34061 User's Guide available on    *
  8.  *  www.spies.com/arcade                                                    *
  9.  *                                                                            *
  10.  ****************************************************************************/
  11.  
  12. #include "driver.h"
  13. #include "vidhrdw/tms34061.h"
  14.  
  15. static void TMS34061_intcallback(int param);
  16.  
  17. #define REG_HORENDSYNC   0
  18. #define REG_HORENDBLNK   1
  19. #define REG_HORSTARTBLNK 2
  20. #define REG_HORTOTAL     3
  21. #define REG_VERENDSYNC   4
  22. #define REG_VERENDBLNK   5
  23. #define REG_VERSTARTBLNK 6
  24. #define REG_VERTOTAL     7
  25. #define REG_DISPUPDATE   8
  26. #define REG_DISPSTART    9
  27. #define REG_VERINT       10
  28. #define REG_CONTROL1     11
  29. #define REG_CONTROL2     12
  30. #define REG_STATUS       13
  31. #define REG_XYOFFSET     14
  32. #define REG_XYADDRESS    15
  33. #define REG_DISPADDRESS  16
  34. #define REG_VERCOUNTER   17
  35.  
  36. static int regs[REG_VERCOUNTER+1];
  37.  
  38. static struct TMS34061interface *intf;
  39.  
  40. static void* timer;
  41.  
  42.  
  43. int TMS34061_start(struct TMS34061interface *interface)
  44. {
  45.     intf = interface;
  46.  
  47.     // Initialize registers to their default values from the manual
  48.     regs[REG_HORENDSYNC]   = 0x10;
  49.     regs[REG_HORENDBLNK]   = 0x20;
  50.     regs[REG_HORSTARTBLNK] = 0x1f0;
  51.     regs[REG_HORTOTAL]     = 0x200;
  52.     regs[REG_VERENDSYNC]   = 0x04;
  53.     regs[REG_VERENDBLNK]   = 0x10;
  54.     regs[REG_VERSTARTBLNK] = 0xf0;
  55.     regs[REG_VERTOTAL]     = 0x100;
  56.     regs[REG_DISPUPDATE]   = 0x00;
  57.     regs[REG_DISPSTART]    = 0x00;
  58.     regs[REG_VERINT]       = 0x00;
  59.     regs[REG_CONTROL1]     = 0x7000;
  60.     regs[REG_CONTROL2]     = 0x600;
  61.     regs[REG_STATUS]       = 0x00;
  62.     regs[REG_XYOFFSET]     = 0x10;
  63.     regs[REG_XYADDRESS]    = 0x00;
  64.     regs[REG_DISPADDRESS]  = 0x00;
  65.     regs[REG_VERCOUNTER]   = 0x00;
  66.  
  67.     // Start vertical interrupt timer.
  68.     timer = timer_pulse(TIME_IN_HZ (Machine->drv->frames_per_second),
  69.                         intf->cpu, TMS34061_intcallback);
  70.     return !timer;
  71. }
  72.  
  73.  
  74. void TMS34061_stop(void)
  75. {
  76.     timer_remove(timer);
  77. }
  78.  
  79.  
  80. INLINE WRITE_HANDLER( TMS34061_register_w )
  81. {
  82.     int status = 0;        // Unsupported
  83.  
  84.     // Calculate which register and which half we're accessing
  85.     int reg = offset >> 2;
  86.  
  87.     // Set register
  88.     if (offset & 0x02)
  89.     {
  90.         // Hi word
  91.         regs[reg] = ((regs[reg] & 0xff) | (data << 8));
  92.     }
  93.     else
  94.     {
  95.         // Lo word
  96.         regs[reg] = ((regs[reg] & 0xff00) | data);
  97.     }
  98.  
  99.     switch (reg)
  100.     {
  101.     case REG_VERINT:
  102.         // Set vertical interrupt timer
  103.         timer_reset(timer, cpu_getscanlinetime(regs[reg]));
  104.  
  105.         // Fall through
  106.  
  107.     case REG_CONTROL1:
  108.     case REG_CONTROL2:
  109.     case REG_XYADDRESS:
  110.         status = 1;        // Ok
  111.         break;
  112.     }
  113.  
  114.     if (!status)
  115.         logerror("Unsupported TMS34061 write. Reg #%02X=%04X - PC: %04X\n",
  116.                 reg, regs[reg], cpu_get_pc());
  117. }
  118.  
  119. static void TMS34061_intcallback(int param)
  120. {
  121.     // Reset timer for next frame
  122. //    timer_reset(timer, cpu_getscanlinetime(regs[REG_VERINT]));
  123.  
  124.     // Get out if vertical interrupts are disabled
  125.     if (!(regs[REG_CONTROL1] & 0x400)) return;
  126.  
  127.     regs[REG_STATUS] |= 0x0001;
  128.  
  129.     cpu_cause_interrupt (param, intf->vertical_interrupt());
  130. }
  131.  
  132.  
  133. INLINE READ_HANDLER( TMS34061_register_r )
  134. {
  135.     int ret;
  136.  
  137.     int status = 0;        // Unsupported
  138.  
  139.     // Calculate which register and which half we're accessing
  140.     int reg = offset >> 2;
  141.  
  142.     // Get register
  143.     if (offset & 0x02)
  144.     {
  145.         // Hi word
  146.         ret = (regs[reg] >> 8);
  147.     }
  148.     else
  149.     {
  150.         // Lo word
  151.         ret = (regs[reg] & 0xff);
  152.     }
  153.  
  154.     switch (reg)
  155.     {
  156.     case REG_STATUS:
  157.         // Need to clear status register now
  158.         regs[reg] = 0;
  159.  
  160.         // Fall through
  161.  
  162.     case REG_CONTROL1:
  163.     case REG_CONTROL2:
  164.     case REG_XYADDRESS:
  165.         status = 1;        // Ok
  166.         break;
  167.     }
  168.  
  169.     if (!status)
  170.         logerror("Unsupported TMS34061 read.  Reg #%02X      - PC: %04X\n",
  171.                 reg, cpu_get_pc());
  172.  
  173.     return ret;
  174. }
  175.  
  176.  
  177. INLINE void adjust_xyaddress(int offset, int x, int y)
  178. {
  179.     // This an implementation of table on Page 4-15 of the User's Guide
  180.     switch (offset & 0x06)
  181.     {
  182.     case 0x00:      break;
  183.     case 0x02: x++; break;
  184.     case 0x04: x--; break;
  185.     case 0x06: x=0; break;
  186.     }
  187.  
  188.     switch (offset & 0x18)
  189.     {
  190.     case 0x00:      break;
  191.     case 0x08: y++; break;
  192.     case 0x10: y--; break;
  193.     case 0x18: y=0; break;
  194.     }
  195.  
  196.     // Currently only implements when the X-Y addresses are 8 bits each
  197.     // Case #7 on Page 4-18 in User's Guide
  198.  
  199.     regs[REG_XYADDRESS] = ((y & 0xff) << 8) | (x & 0xff);
  200. }
  201.  
  202. INLINE WRITE_HANDLER( TMS34061_xypixel_w )
  203. {
  204.     // Currently only implements when the X-Y addresses are 8 bits each
  205.     // Case #7 on Page 4-18 in User's Guide
  206.  
  207.     int x = regs[REG_XYADDRESS] & 0xff;
  208.     int y = regs[REG_XYADDRESS] >> 8;
  209.  
  210.     intf->setpixel(x, y, data);
  211.  
  212.     if (offset) adjust_xyaddress(offset, x, y);
  213. }
  214.  
  215.  
  216. INLINE READ_HANDLER( TMS34061_xypixel_r )
  217. {
  218.     // Currently only implements when the X-Y addresses are 8 bits each
  219.     // Case #7 on Page 4-18 in User's Guide
  220.  
  221.     int x = regs[REG_XYADDRESS] & 0xff;
  222.     int y = regs[REG_XYADDRESS] >> 8;
  223.  
  224.     int ret = intf->getpixel(x, y);
  225.  
  226.     if (offset) adjust_xyaddress(offset, x, y);
  227.  
  228.     return ret;
  229. }
  230.  
  231.  
  232. WRITE_HANDLER( TMS34061_w )
  233. {
  234.     int col = intf->getcoladdress(offset);
  235.     int row = intf->getrowaddress(offset);
  236.  
  237.     /* Get function code and call appropriate handler */
  238.     int func = intf->getfunction(offset);
  239.     switch (func)
  240.     {
  241.     case 0:
  242.     case 2:  /* Register access */
  243.         TMS34061_register_w(col, data);
  244.         break;
  245.  
  246.     case 1:  /* XY access. Note: col is really the address adjustment function.
  247.                 The real col and row comes from the XY address registers */
  248.         TMS34061_xypixel_w(col, data);
  249.         break;
  250.  
  251.     case 3:  /* Direct access */
  252.         intf->setpixel(col, row, data);
  253.         break;
  254.  
  255.     default:
  256.         logerror("Unsupported TMS34061 function %d - PC: %04X\n",
  257.                 func, cpu_get_pc());
  258.     }
  259. }
  260.  
  261. READ_HANDLER( TMS34061_r )
  262. {
  263.     int ret = 0;
  264.  
  265.     int col = intf->getcoladdress(offset);
  266.     int row = intf->getrowaddress(offset);
  267.  
  268.     /* Get function code and call appropriate handler */
  269.     int func = intf->getfunction(offset);
  270.     switch (func)
  271.     {
  272.     case 0:
  273.     case 2:  /* Register access */
  274.         ret = TMS34061_register_r(col);
  275.         break;
  276.  
  277.     case 1:  /* XY access. Note: col is really the address adjustment code.
  278.                 The real col and row comes from the XY address registers */
  279.         ret = TMS34061_xypixel_r(col);
  280.         break;
  281.  
  282.     case 3:  /* Direct access */
  283.         ret = intf->getpixel(col, row);
  284.         break;
  285.  
  286.     default:
  287.         logerror("Unsupported TMS34061 function %d - PC: %04X\n",
  288.                 func, cpu_get_pc());
  289.     }
  290.  
  291.     return ret;
  292. }
  293.  
  294.  
  295. int TMS34061_display_blanked(void)
  296. {
  297.     return (!(regs[REG_CONTROL2] & 0x2000));
  298. }
  299.  
  300.